package org.realogic.cfm.persistence.mybatis;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

import org.apache.ibatis.executor.BatchResult;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.session.SqlSession;
import org.mybatis.spring.SqlSessionTemplate;
import org.realogic.cfm.persistence.KDataSourceRepository;
import org.realogic.cfm.persistence.query.QueryCondition;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.dao.DataAccessException;

/**
 * MyBatis基础DAO
 * 
 * @since 2015-08-10
 * @author chenkq
 * 
 * @param <E>
 */
public abstract class MyBatisDao2<E> {

	/*
	 * SqlSessionFactoryBeanRepository：：SqlSessionTemplate对象管理器，支持多数据源。
	 */
	private KDataSourceRepository dataSourceRepository;

	public KDataSourceRepository getDataSourceRepository() {
		return dataSourceRepository;
	}

	@Autowired
	@Qualifier("cfm.dataSourceRepository")
	public void setDataSourceRepository(KDataSourceRepository dataSourceRepository) {
		this.dataSourceRepository = dataSourceRepository;
	}

	/**
	 * 获取SqlSessionTemplate对象
	 * 
	 * @param aDataSourcName
	 *            数据源名称
	 * @return SqlSession 实际是SqlSessionTemplate类型
	 */
	public SqlSession getSqlSessionTemplate(String aDataSourcName) {
		String temp = aDataSourcName;
		if (temp == null || "".equals(aDataSourcName)) {
			temp = dataSourceRepository.getDefaultDataSourceName();
		}
		SqlSessionTemplate tmpSqlSessionTemplate = dataSourceRepository.getSqlSessionTemplateMap().get(temp);
		if (tmpSqlSessionTemplate == null) {
			tmpSqlSessionTemplate = dataSourceRepository.getDefaultSqlSessionTemplate();
		}
		return tmpSqlSessionTemplate;
	}

	/**
	 * 获取默认的SqlSessionTemplate对象
	 * 
	 * @return
	 */
	public SqlSession getSqlSessionTemplate() {
		return getSqlSessionTemplate(null);
	}

	/**
	 * Simple Execute
	 * 
	 * @param aWorkUnit
	 *            MyBatis工作单元
	 * @param aDataSourcName
	 *            数据源名
	 * @return
	 */
	public <T> T executeSimple(final String aDataSourcName, final MyBatisWorkUnit<T> aWorkUnit) {
		SqlSession session = null;
		// try {
		session = getSqlSessionTemplate(aDataSourcName);
		return aWorkUnit.doInSession(session);
		// } finally {
		// if (session != null) {
		// session.close();
		// }
		// }
	}

	/**
	 * Simple Execute (默认数据源)
	 * 
	 * @param aWorkUnit
	 *            MyBatis工作单元
	 * @return
	 */
	public <T> T executeSimple(final MyBatisWorkUnit<T> aWorkUnit) {
		return executeSimple(null, aWorkUnit);
	}

	/**
	 * 批处理操作
	 * 
	 * @param aWorkUnit
	 *            MyBatis工作单元
	 * @param aDataSourcName
	 *            数据源名
	 * @return int 影响的记录数
	 */
	public <T> int executeBatch(final String aDataSourcName, final MyBatisWorkUnit<T> aWorkUnit) {
		SqlSessionTemplate sessionTemplate = null;
		SqlSession session = null;
		List<BatchResult> tmpResult = null;
		int flag = 0;
		try {
			sessionTemplate = (SqlSessionTemplate) getSqlSessionTemplate(aDataSourcName);
			session = sessionTemplate.getSqlSessionFactory().openSession(ExecutorType.BATCH, false);
			aWorkUnit.doInSession(session);
			tmpResult = session.flushStatements();
			session.commit();
			session.clearCache();
			if (tmpResult != null) {
				for (BatchResult tmp : tmpResult) {
					int x[] = tmp.getUpdateCounts();
					for (int i = 0; i < x.length; i++) {
						flag += x[i];
					}
				}
			}
		} finally {
			if (session != null) {
				session.close();
			}
		}
		return flag;
	}

	public int insert(final String aDataSourcName, final String aStatement, final E aEntity) {
		SqlSession session = getSqlSessionTemplate(aDataSourcName);
		return session.insert(aStatement, aEntity);
	}

	public int insert(final String aStatement, final E aEntity) {
		return this.insert(null, aStatement, aEntity);
	}

	public int update(final String aDataSourcName, final String aStatement, final E aEntity) {
		SqlSession session = getSqlSessionTemplate(aDataSourcName);
		return session.update(aStatement, aEntity);
	}

	public int update(final String aStatement, final E aEntity) {
		SqlSession session = getSqlSessionTemplate();
		return session.update(aStatement, aEntity);
	}

	public int updateBatch(final String aDataSourcName, final String aStatement, final List<E> aEntityList) {
		return executeBatch(aDataSourcName, new MyBatisWorkUnit<Integer>() {
			public Integer doInSession(SqlSession session) {
				int flag = 1;
				try {
					for (int i = 0, size = aEntityList.size(); i < size; i++) {
						session.update(aStatement, aEntityList.get(i));
					}
				} catch (DataAccessException e) {
					flag = -1;
					throw e;
				}
				return flag;
			}
		});
	}

	public int updateBatch(final String aStatement, final List<E> aEntityList) {
		return updateBatch(null, aStatement, aEntityList);
	}

	public int insertBatch(final String aDataSourcName, final String aStatement, final List<E> aEntityList) {
		return executeBatch(aDataSourcName, new MyBatisWorkUnit<Integer>() {
			public Integer doInSession(SqlSession session) {
				int flag = 1;
				try {
					for (int i = 0, size = aEntityList.size(); i < size; i++) {
						session.insert(aStatement, aEntityList.get(i));
					}
				} catch (DataAccessException e) {
					flag = -1;
					throw e;
				}
				return flag;
			}
		});
	}

	public int insertBatch(final String aStatement, final List<E> aEntityList) {
		return insertBatch(null, aStatement, aEntityList);
	}

	public int deleteBatch(final String aDataSourcName, final String aStatement, final List<E> aEntityList) {
		return executeBatch(aDataSourcName, new MyBatisWorkUnit<Integer>() {
			public Integer doInSession(SqlSession session) {
				int flag = 1;
				try {
					for (int i = 0, size = aEntityList.size(); i < size; i++) {
						session.delete(aStatement, aEntityList.get(i));
					}
				} catch (DataAccessException e) {
					flag = -1;
					throw e;
				}
				return flag;
			}
		});
	}

	public int deleteBatch(final String aStatement, final List<E> aEntityList) {
		return deleteBatch(null, aStatement, aEntityList);
	}

	public int delete(final String aDataSourcName, final String aStatement, final Serializable aPK) {
		SqlSession session = getSqlSessionTemplate(aDataSourcName);
		return session.delete(aStatement, aPK);
	}

	public int delete(final String aStatement, final Serializable aPK) {
		SqlSession session = getSqlSessionTemplate();
		return session.delete(aStatement, aPK);
	}

	/**
	 * 
	 * @param aStatement
	 * @param aPK
	 * @return
	 */
	public Object selectOneForObject(final String aStatement, final Serializable aPK) {
		SqlSession session = getSqlSessionTemplate();
		return session.selectOne(aStatement, aPK);
	}

	public int selectOneForInt(final String aStatement, final Object aPK) {
		SqlSession session = getSqlSessionTemplate();
		return session.selectOne(aStatement, aPK);
	}

	public E selectOne(final String aDataSourcName, final String aStatement, final Serializable aPK) {
		SqlSession session = getSqlSessionTemplate(aDataSourcName);
		return session.selectOne(aStatement, aPK);
	}

	public E selectOne(final String aStatement, final Serializable aPK) {
		SqlSession session = getSqlSessionTemplate();
		return session.selectOne(aStatement, aPK);
	}

	/**
	 * 带分页的查询
	 * 
	 * @param aStatement
	 * @param aCondition
	 * @param aRowBounds
	 * @return List<E>
	 */
	public List<E> selectList(final String aStatement, final Map<String, Object> aCondition, RowBounds aRowBounds) {
		SqlSession session = getSqlSessionTemplate();
		return session.selectList(aStatement, aCondition, aRowBounds);
	}

	/**
	 * 不带分页查询
	 * 
	 * @param aStatement
	 * @param aCondition
	 *            Map参数
	 * @return List<E>
	 */
	public List<E> selectList(final String aStatement, final Map<String, Object> aCondition) {
		SqlSession session = getSqlSessionTemplate();
		return session.selectList(aStatement, aCondition);
	}

	/**
	 * 按某一Serializable对象条件查询
	 * 
	 * @param aStatement
	 * @param aPK
	 * @return List<E>
	 */
	public List<E> selectList(final String aStatement, final Serializable aPK) {
		SqlSession session = getSqlSessionTemplate();
		return session.selectList(aStatement, aPK);
	}

	/**
	 * 按某一QueryCondition对象条件查询
	 * 
	 * @param aStatement
	 * @param theCondition
	 *            theCondition
	 * @return List<E>
	 */
	public List<E> selectList(final String aStatement, final QueryCondition theCondition) {
		SqlSession session = getSqlSessionTemplate();
		return session.selectList(aStatement, theCondition);
	}

}
